package com.ais.gaea;

import com.ais.gaea.annotation.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author xuning
 * @date 2022/11/26 18:50
 */
@Slf4j
public class AnnotationUtils {
	/**
	 * 扫描packagePath路径下，所有标注annotationClazz注解的类
	 *
	 * @param tablePackageName 包名
	 * @param annotationClazz 指定的注解类型
	 * @return 返回包含指定注解的所有类
	 */
	public static Set<Class<?>> scan(String tablePackageName, Class<? extends Annotation> annotationClazz) {
		Assert.hasLength(tablePackageName, "table package location must not be empty");
		Assert.notNull(annotationClazz,"annotation must not be null");

		PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		SimpleMetadataReaderFactory register = new SimpleMetadataReaderFactory();
		StandardEnvironment environment = new StandardEnvironment();

		String clazzPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
				+ ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(tablePackageName))
				+ '/' + "**/*.class";
		Set<Class<?>> clazzSet = new HashSet<>();
		Resource[] resources;
		try {
			//加载路径
			resources = resolver.getResources(clazzPattern);
		} catch (IOException e) {
			log.error("search class in {} path failed", clazzPattern, e);
			throw new RuntimeException(e);
		}
		for (Resource resource : resources) {
			MetadataReader metadataReader;
			try {
				//读取资源
				metadataReader = register.getMetadataReader(resource);
			} catch (IOException e) {
				continue;
			}
			//读取资源的注解配置
			AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
			//判断是否包含注解
			if (!annotationMetadata.hasAnnotation(annotationClazz.getName())) {
				continue;
			}
			//类信息
			ClassMetadata classMetadata = metadataReader.getClassMetadata();
			//类全名
			String className = classMetadata.getClassName();
			try {
				//加载类
				Class<?> clazz = Class.forName(className);
				clazzSet.add(clazz);
			} catch (ClassNotFoundException e) {
				log.error("{} class not found", className, e);
			}
		}
		return clazzSet;
	}


	public static String getTableName(Class<?> table) {
		Table annotation = table.getAnnotation(Table.class);
		return annotation.name();
	}

	public static String getTableMultiTenantValue(Class<?> table) {
		Table annotation = table.getAnnotation(Table.class);
		return annotation.multiTenant();
	}

	public static String getTableComment(Class<?> table){
		Table annotation = table.getAnnotation(Table.class);
		return annotation.comment();
	}

	public static TableColumn[] getTableColumns(Class<?> table) {
		List<TableColumn> tableColumns = new ArrayList<>();
		Field[] declaredFields = table.getDeclaredFields();
		for (Field declaredField : declaredFields) {
			if (declaredField.isAnnotationPresent(TableColumn.class)) {
				tableColumns.add(declaredField.getAnnotation(TableColumn.class));
			}
		}
		return tableColumns.toArray(new TableColumn[0]);
	}

	public static TableConstraint[] getTableConstraint(Class<?> table) {
		return table.getAnnotationsByType(TableConstraint.class);
	}

	public static TableIndex[] getTableIndex(Class<?> table) {
		return table.getAnnotationsByType(TableIndex.class);
	}

	public static TableConfiguration getTableConfiguration(Class<?> table) {
		return table.getAnnotation(TableConfiguration.class);
	}

}
